#ifndef __ITERATOR__
#define __ITERATOR__

#include <Function.h>

template<typename T>
struct CIterator
	{
	virtual TBool HasNext() = 0;
	virtual TBool Next(T& ) = 0;
	virtual void Reset() = 0;
	virtual ~CIterator() { }
	};


template<typename T>
struct CFilteringIterator : public CIterator<T>
	{
	CIterator<T>* iUnderlying;
	LManagedPtr< scalp::CFunction<TBool(const T&)> > iFun;
	
	CFilteringIterator(CIterator<T>* aUnderlying, scalp::CFunction<TBool(const T&)>* aFun)
	: iUnderlying(aUnderlying), iFun(aFun)
		{
		
		}
	
	TBool HasNext()
	{
		return iUnderlying->HasNext();
	}
	TBool Next(T& aNext)
	{
		TBool ret ( iUnderlying->Next(aNext) && (*iFun)(aNext) );
		return( ret );
	}
	void Reset()
		{
		iUnderlying->Reset();
		}
	};



template<typename T>
struct CArrayIterator : public CIterator<T>
	{
	T* iArray;
	TUint iSize;
	TUint iCurrent;
	CArrayIterator(T* aArray, TUint aSize) : iArray(aArray), iSize(aSize), iCurrent(0) { }
	TBool HasNext()
	{
		return iCurrent < iSize;
	}
	TBool Next(T& aNext)
	{
		aNext = iArray[iCurrent++];
		return ETrue;
	}
	void Reset()
		{
		iCurrent = 0;
		}
	
	};


template<typename T>
struct CArrayPtrIterator;

template<typename T>
struct CArrayPtrIterator<T*> : public CIterator<T*>
	{
	T* iArray;
	TUint iSize;
	TUint iCurrent;
	CArrayPtrIterator(T* aArray, TUint aSize) : iArray(aArray), iSize(aSize), iCurrent(0) { }
	TBool HasNext()
	{
		return iCurrent < iSize;
	}
	TBool Next(T*& aNext)
	{
		aNext = &(iArray[iCurrent++]);
		return ETrue;
	}
	void Reset()
		{
		iCurrent = 0;
		}
	
	};


template<typename T, typename K>
struct COrderingIterator : public CIterator<T>
	{
	struct TPtr_TKey { T iPtr; K iKey; };
	RArray<TPtr_TKey> iPtrs;
	CIterator<T>* iUnderlying;
	LManagedPtr< scalp::CFunction<K(const T&)> > iFun;
	TBool iUnderlyingHasNext;
	TInt iCurrent;
	TBool iDirty;
	TBool iSorted;
	
	COrderingIterator(CIterator<T>* aUnderlying, scalp::CFunction<K(const T&)>* aFun)
	: iUnderlying(aUnderlying), iFun(aFun), iUnderlyingHasNext(ETrue), iCurrent(0), iDirty(EFalse), iSorted(EFalse)
		{
		
		}
	~COrderingIterator()
		{
		iPtrs.Close();
		}

	void Reset()
		{
		if(iDirty)
			{
			iUnderlying->Reset();
			iUnderlyingHasNext = ETrue;
			iPtrs.Reset();
			iSorted = EFalse;
			iDirty = EFalse;
			}
		iCurrent = 0;
		}
	
	void SetDirty(TBool aBool)
		{
		iDirty = aBool;
		}
	
	TBool HasNext()
	{
		iUnderlyingHasNext = iUnderlying->HasNext();
		if(!iUnderlyingHasNext)
			{
			if(iCurrent == iPtrs.Count())
				return EFalse;
			else
				return ETrue;
			}
		else return ETrue;
	}
	TBool Next(T& aNext)
	{
		if(iUnderlyingHasNext)
			{
			if( iUnderlying->Next(aNext) )
				{
				TPtr_TKey entry = { aNext, (*iFun)(aNext) };
				iPtrs.Append( entry );
				}
			return EFalse;
			}
		else
			{
			if(!iSorted)
				{
				iPtrs.Sort(TLinearOrder<TPtr_TKey>(&TLinearOrder_TPtr_TKey));
				iSorted = ETrue;
				}
			aNext = iPtrs[iCurrent++].iPtr;
			return ETrue;
			}
	}
	
private:
	static TInt TLinearOrder_TPtr_TKey(const TPtr_TKey& left, const TPtr_TKey& right)
		{
		if (left.iKey < right.iKey) return -1;
		if (left.iKey == right.iKey) return 0;
		return 1;
		}
	
	};


#endif
